home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2001 May / may_2001.iso / intercd / root / Multimedia / ^DivX_Article / virtualdub / VirtualDub-source-1_4d / vdsvrlnk / main.cpp next >
Encoding:
C/C++ Source or Header  |  2000-09-22  |  11.6 KB  |  498 lines

  1. #include <crtdbg.h>
  2.  
  3. #include <windows.h>
  4.  
  5.  
  6. namespace Windows95 {
  7.  
  8. #include <svrapi.h>
  9.  
  10. };
  11.  
  12.  
  13. #include <lmcons.h>
  14. #include <lmserver.h>
  15. #include <lmapibuf.h>
  16. #include <vfw.h>
  17.  
  18. #define BUILDING_VDSVRLNK_DLL
  19. #include "vdserver.h"
  20.  
  21. typedef struct VDubPostedFrameserver {
  22.     HWND hwndServer;
  23.     int active_connects;
  24.     char name[56];
  25. } VDubPostedFrameserver;
  26.  
  27. #define MAXIMUM_FRAMESERVERS (256)
  28.  
  29. typedef struct VDubSharedHeap {
  30.     char    comp_name[16];
  31.     int        total_frameservers;
  32.     int        last_alloc;
  33.     DWORD    next_mmapID;
  34.     VDubPostedFrameserver fs_table[MAXIMUM_FRAMESERVERS];
  35. } VDubSharedHeap;
  36.  
  37. ////////////////////////////////////////////
  38.  
  39. VDubSharedHeap *heap;
  40. HANDLE            hHeap;
  41. HANDLE            hMutex;
  42.  
  43. ////////////////////////////////////////////
  44.  
  45. typedef    int (APIENTRY *LPNETSERVERGETINFO95)(
  46.                 const char FAR *     pszServer,
  47.                 short                sLevel,
  48.                 char FAR *           pbBuffer,
  49.                 unsigned short       cbBuffer,
  50.                 unsigned short FAR * pcbTotalAvail);
  51.  
  52. typedef    NET_API_STATUS (APIENTRY *LPNETSERVERGETINFONT)(
  53.                 LPWSTR                servername,
  54.                 DWORD                level,
  55.                 LPBYTE                *bufptr);
  56.  
  57. static void InitComputerAlias() {
  58.     union {
  59.         struct Windows95::server_info_50 si_95;
  60.         char buf[2048];
  61.     } si;
  62.     unsigned short needed_size;
  63.     HMODULE hDll = NULL;
  64.     FARPROC fpNetServerGetInfo = NULL;
  65.  
  66.     // For Windows 95, NetServerGetInfo() is in SVRAPI.DLL
  67.     // For Windows NT, NetServerGetInfo() is in NETAPI32.DLL
  68.     //
  69.     // Rather than test for the OS as Microsoft suggests, we simply
  70.     // try SVRAPI.DLL first, and then NETAPI32.  If both fail, then
  71.     // fake a computer name with 'ANON' and then 8 hex digits of the
  72.     // current tick value.
  73.  
  74.     if (hDll = LoadLibrary("svrapi.dll")) {
  75.         fpNetServerGetInfo = GetProcAddress(hDll, "NetServerGetInfo");
  76.  
  77.         if (fpNetServerGetInfo && !((LPNETSERVERGETINFO95)fpNetServerGetInfo)(NULL, 50, (char *)&si, sizeof si, &needed_size)) {
  78.             strncpy(heap->comp_name, si.si_95.sv50_name, sizeof heap->comp_name);
  79.             heap->comp_name[sizeof heap->comp_name-1] = 0;
  80.  
  81.             FreeLibrary(hDll);
  82.             return;
  83.         }
  84.  
  85.         FreeLibrary(hDll);
  86.     }
  87.  
  88.     // Okay, that didn't work -- try Windows NT/2000.
  89.  
  90.     if (!fpNetServerGetInfo && (hDll = LoadLibrary("netapi32.dll"))) {
  91.         SERVER_INFO_100 *psi100;
  92.  
  93.         fpNetServerGetInfo = GetProcAddress(hDll, "NetServerGetInfo");
  94.         if (fpNetServerGetInfo && !((LPNETSERVERGETINFONT)fpNetServerGetInfo)(NULL, 100, (LPBYTE *)&psi100)) {
  95.  
  96.             WideCharToMultiByte(CP_ACP, 0,  (LPWSTR)psi100->sv100_name, -1, heap->comp_name, sizeof heap->comp_name, NULL, NULL);
  97. //            strncpy(heap->comp_name, psi100->sv100_name, sizeof heap->comp_name);
  98. //            heap->comp_name[sizeof heap->comp_name-1] = 0;
  99.  
  100.             void *lpNetApiBufferFree;
  101.  
  102.             if (lpNetApiBufferFree = GetProcAddress(hDll, "NetApiBufferFree"))
  103.                 ((NET_API_STATUS (APIENTRY *)(LPVOID ))lpNetApiBufferFree)(psi100);
  104.  
  105.             FreeLibrary(hDll);
  106.             return;
  107.         }
  108.  
  109.         FreeLibrary(hDll);
  110.     }
  111.  
  112.     // Ugh.
  113.  
  114.     wsprintf(heap->comp_name, "Anon%08lx", GetTickCount());
  115. }
  116.  
  117. static BOOL InitSharedSpace() {
  118.     BOOL fInit;
  119.  
  120.     //////////
  121.  
  122.     hHeap = CreateFileMapping(    (HANDLE)0xFFFFFFFF,
  123.                                 NULL,
  124.                                 PAGE_READWRITE,
  125.                                 0,
  126.                                 sizeof(VDubSharedHeap),
  127.                                 "VirtualDub Server System Window");
  128.  
  129.     if (hHeap == NULL) return FALSE;
  130.  
  131.     _RPT0(0,"shared heap created\n");
  132.  
  133.     fInit = (GetLastError() != ERROR_ALREADY_EXISTS);
  134.  
  135.     heap = (VDubSharedHeap *)MapViewOfFile(
  136.                                 hHeap,
  137.                                 FILE_MAP_WRITE,
  138.                                 0,
  139.                                 0,
  140.                                 0);
  141.  
  142.     if (!heap) {
  143.         CloseHandle(hHeap);
  144.         return FALSE;
  145.     }
  146.  
  147.     _RPT0(0,"heap mapped into subspace... preparing to go to warp.\n");
  148.  
  149.     if (!(hMutex = CreateMutex(NULL, FALSE, "VirtualDub Server System Mutex")))
  150.         return FALSE;
  151.  
  152.     _RPT0(0,"mutex obtained\n");
  153.  
  154.     if (!fInit) return TRUE;
  155.  
  156.     memset(heap, 0, sizeof VDubSharedHeap);
  157.  
  158.     InitComputerAlias();
  159.  
  160.     return TRUE;
  161. }
  162.  
  163. // Are you a Ranma 1/2 fan?
  164.  
  165. static void ranko() {
  166.     _RPT1(0,"server: lock mutex %p\n", hMutex);
  167.     WaitForSingleObject(hMutex, INFINITE);
  168. }
  169.  
  170. static void ranma() {
  171.     _RPT1(0,"server: unlock mutex %p\n", hMutex);
  172.     if (!ReleaseMutex(hMutex))
  173.         _RPT0(0,"Hey!  I didn't own the mutex!\n");
  174. }
  175.  
  176. ////////////////////////////////////////////
  177.  
  178. //extern "C" __declspec(dllexport) BOOL WINAPI DllMain(HANDLE hModule, ULONG ulReason, LPVOID lpReserved);
  179.  
  180. HMODULE ghModule;
  181.  
  182. BOOL APIENTRY DllMain(HANDLE hModule, ULONG ulReason, LPVOID lpReserved) {
  183.  
  184.     switch(ulReason) {
  185.     case DLL_PROCESS_ATTACH:
  186.         ghModule = (HMODULE)hModule;
  187.  
  188.         _RPT0(0,"Process attach\n");
  189.  
  190.         return InitSharedSpace();
  191.  
  192.     case DLL_PROCESS_DETACH:
  193.         UnmapViewOfFile(heap);
  194.         CloseHandle(hHeap);
  195.         break;
  196.     }
  197.  
  198.     return TRUE;
  199. }
  200.  
  201. /////////////////////////////////////////////
  202.  
  203. class CVDubAnimConnection : public IVDubAnimConnection {
  204. private:
  205.     VDubPostedFrameserver *frameserver;
  206.     HANDLE hArena;
  207.     char *arena;
  208.     long lArenaSize;
  209.     DWORD dwSessionID;
  210.     long lFrameSize;
  211.  
  212. public:
  213.     CVDubAnimConnection(VDubPostedFrameserver *);
  214.     ~CVDubAnimConnection();
  215.  
  216.     BOOL init();
  217.  
  218.     BOOL hasAudio();
  219.     BOOL readStreamInfo(AVISTREAMINFO *lpsi, BOOL fAudio, long *lpFirst, long *lpLast);
  220.     int readFormat(void *ptr, BOOL fAudio);
  221.     int readVideo(long lSample, void *lpBuffer);
  222.     int readAudio(long lSample, long lCount, void *lpBuffer, long cbBuffer, long *lplBytes, long *lplSamples);
  223. };
  224.  
  225.  
  226. ///////////////////////////////////////////
  227.  
  228. CVDubAnimConnection::CVDubAnimConnection(VDubPostedFrameserver *vdpf) {
  229.     frameserver = vdpf;
  230.     dwSessionID = 0;
  231.     hArena = INVALID_HANDLE_VALUE;
  232.     arena = NULL;
  233. }
  234.  
  235. CVDubAnimConnection::~CVDubAnimConnection() {
  236.     if (dwSessionID) SendMessage(frameserver->hwndServer, VDSRVM_CLOSE, 0, dwSessionID);
  237.  
  238.     if (arena) UnmapViewOfFile(arena);
  239.     if (hArena) CloseHandle(hArena);
  240.  
  241.     --frameserver->active_connects;
  242. }
  243.  
  244. BOOL CVDubAnimConnection::init() {
  245.     LONG lArenaSize;
  246.     char buf[16];
  247.     DWORD mmapID;
  248.  
  249.     // find out how big of an arena we need
  250.  
  251.     lArenaSize = SendMessage(frameserver->hwndServer, VDSRVM_BIGGEST, 0, 0);
  252.  
  253.     if (!lArenaSize) return FALSE;
  254.  
  255.     // create a name for us
  256.  
  257.     ranko();
  258.     wsprintf(buf, "VDUBF%08lx", mmapID = heap->next_mmapID++);
  259.     ranma();
  260.  
  261.     // create a shared arena and map a window for us
  262.  
  263.     hArena = CreateFileMapping(
  264.             (HANDLE)0xFFFFFFFF,
  265.             NULL,
  266.             PAGE_READWRITE,
  267.             0,
  268.             lArenaSize,
  269.             buf);
  270.  
  271.     if (!hArena) return FALSE;
  272.  
  273.     _RPT0(0,"Have arena.\n");
  274.  
  275.     arena = (char *)MapViewOfFile(hArena, FILE_MAP_WRITE, 0, 0, lArenaSize);
  276.  
  277.     if (!arena) return FALSE;
  278.  
  279.     _RPT0(0,"Arena mapped.\n");
  280.  
  281.     // hail the server
  282.  
  283.     dwSessionID = SendMessage(frameserver->hwndServer, VDSRVM_OPEN, lArenaSize, mmapID);
  284.  
  285.     if (!dwSessionID) return FALSE;        // no response, Captain
  286.  
  287.     _RPT0(0,"Server responded.\n");
  288.  
  289.     // on screen!  get me the video format!
  290.  
  291.     if (SendMessage(frameserver->hwndServer, VDSRVM_REQ_FORMAT, 0, dwSessionID) <= 0)
  292.         return FALSE;
  293.  
  294.     {
  295.         BITMAPINFOHEADER *bmih = (BITMAPINFOHEADER *)arena;
  296.  
  297.         lFrameSize = bmih->biSizeImage;
  298.     }
  299.  
  300.     _RPT0(0,"Connect!\n");
  301.  
  302.     return TRUE;
  303. }
  304.  
  305. BOOL CVDubAnimConnection::hasAudio() {
  306.     return VDSRVERR_OK == SendMessage(frameserver->hwndServer, VDSRVM_REQ_STREAMINFO, 1, dwSessionID);
  307. }
  308.  
  309. BOOL CVDubAnimConnection::readStreamInfo(AVISTREAMINFO *lpsi, BOOL fAudio, long *lpFirst, long *lpLast) {
  310.     if (VDSRVERR_OK == SendMessage(frameserver->hwndServer, VDSRVM_REQ_STREAMINFO, !!fAudio, dwSessionID)) {
  311.         if (lpsi) memcpy(lpsi, arena+8, sizeof(AVISTREAMINFO));
  312.         if (lpFirst) *lpFirst = *(long *)(arena+0);
  313.         if (lpLast) *lpLast = *(long *)(arena+4);
  314.         return TRUE;
  315.     }
  316.     return FALSE;
  317. }
  318.  
  319. int CVDubAnimConnection::readFormat(void *ptr, BOOL fAudio) {
  320.     int err;
  321.  
  322.     err = SendMessage(frameserver->hwndServer, VDSRVM_REQ_FORMAT, !!fAudio, dwSessionID);
  323.  
  324.     if (err<0) return err;
  325.  
  326.     if (ptr) memcpy(ptr, arena, err);
  327.  
  328.     return err;
  329. }
  330.  
  331. int CVDubAnimConnection::readVideo(long lSample, void *lpBuffer) {
  332.     int err;
  333.  
  334.     _RPT0(0,"Sending message...\n");
  335.     if (VDSRVERR_OK != (err = SendMessage(frameserver->hwndServer, VDSRVM_REQ_FRAME, lSample, dwSessionID)))
  336.         return err;
  337.  
  338.     _RPT2(0,"Copying %ld bytes to user buffer from arena %P\n", lFrameSize, arena);
  339.     memcpy(lpBuffer, arena, lFrameSize);
  340.     _RPT0(0,"Copy completed.\n");
  341.  
  342.     return VDSRVERR_OK;
  343. }
  344.  
  345. int CVDubAnimConnection::readAudio(long lSample, long lCount, void *lpBuffer, long cbBuffer, long *lplBytes, long *lplSamples) {
  346.     int err;
  347.  
  348.     *(long *)(arena+0) = lCount;
  349.     *(long *)(arena+4) = cbBuffer;
  350.  
  351.     if (VDSRVERR_OK != (err = SendMessage(frameserver->hwndServer, lpBuffer?VDSRVM_REQ_AUDIO:VDSRVM_REQ_AUDIOINFO, lSample, dwSessionID)))
  352.         return err;
  353.  
  354.     if (lplSamples) *lplSamples = *(long *)(arena + 4);
  355.     if (lplBytes) *lplBytes = *(long *)(arena + 0);
  356.  
  357.     if (lpBuffer) memcpy(lpBuffer, arena+8, *lplBytes);
  358.  
  359.     return VDSRVERR_OK;
  360. }
  361.  
  362. /////////////////////////////////////////////////////////////////////////////
  363. //
  364. //        CVDubServerLink
  365. //
  366. /////////////////////////////////////////////////////////////////////////////
  367.  
  368. class CVDubServerLink : public IVDubServerLink {
  369. public:
  370.     void                    GetComputerName(char *buf);
  371.     IVDubAnimConnection    *    FrameServerConnect(char *fs_name);
  372.     void                    FrameServerDisconnect(IVDubAnimConnection *);
  373.     int                        CreateFrameServer(char *name, HWND hwndServer);
  374.     void                    DestroyFrameServer(int handle);
  375. };
  376.  
  377. static CVDubServerLink i_dubserver;
  378.  
  379. void CVDubServerLink::GetComputerName(char *buf) {
  380.     lstrcpy(buf, heap->comp_name);
  381. }
  382.  
  383. IVDubAnimConnection *CVDubServerLink::FrameServerConnect(char *fs_name) {
  384.     int i;
  385.     char c,*s;
  386.     CVDubAnimConnection *cvdac;
  387.  
  388.     // look for a slash (/) that delimits the computer name
  389.  
  390.     _RPT1(0,"Looking for server [%s]\n",fs_name);
  391.  
  392.     s = fs_name;
  393.     while(c=*s++) if (c=='/') {
  394.         char *s1, *s2, d;
  395.  
  396.         // we found the slash... now compare that to our computer name
  397.  
  398.         s1 = fs_name;
  399.         s2 = heap->comp_name;
  400.  
  401.         do {
  402.             c = *s1++;
  403.             d = *s2++;
  404.         } while(c==d && c!='/' && d);
  405.  
  406.         if (c!='/' || d)
  407.             return NULL;    // not our computer, and we don't do remote yet
  408.  
  409.         // yay!  it's us!
  410.  
  411.         break;
  412.     }
  413.  
  414.     if (!c) s=fs_name;
  415.  
  416.     // look through the list and see if we can spot the server
  417.  
  418.     _RPT1(0,"Computer name ok, looking for server [%s]\n", s);
  419.  
  420.     ranko();
  421.  
  422.     for(i=0; i<MAXIMUM_FRAMESERVERS; i++) {
  423.         if (heap->fs_table[i].hwndServer && !stricmp(heap->fs_table[i].name, s))
  424.             break;
  425.     }
  426.  
  427.     if (i >= MAXIMUM_FRAMESERVERS) {
  428.         _RPT0(0,"Computer not found\n");
  429.         ranma();
  430.         return NULL;
  431.     }
  432.  
  433.     // hey!  we spotted the server!  now lock it before it goes
  434.     // away!
  435.  
  436.     _RPT0(0,"Server found\n");
  437.  
  438.     ++heap->fs_table[i].active_connects;
  439.  
  440.     // allocate a CVDubAnimConnection
  441.  
  442.     if (cvdac = new CVDubAnimConnection(&heap->fs_table[i])) {
  443.         // try to initialize it
  444.  
  445.         if (!cvdac->init()) {
  446.             delete cvdac;
  447.             cvdac = NULL;
  448.         }
  449.     } else --heap->fs_table[i].active_connects;
  450.  
  451.     ranma();
  452.  
  453.     return cvdac;
  454. }
  455.  
  456. void CVDubServerLink::FrameServerDisconnect(IVDubAnimConnection *idac) {
  457.     delete (CVDubAnimConnection *)idac;
  458. }
  459.  
  460. int CVDubServerLink::CreateFrameServer(char *name, HWND hwndServer) {
  461.     int i;
  462.  
  463.     if (heap->total_frameservers >= MAXIMUM_FRAMESERVERS)
  464.         return -1;
  465.  
  466.     ranko();
  467.  
  468.     i = heap->last_alloc;
  469.     while(heap->fs_table[i].active_connects || heap->fs_table[i].hwndServer)
  470.         i = (i+1) % MAXIMUM_FRAMESERVERS;
  471.  
  472.     heap->fs_table[i].hwndServer = hwndServer;
  473.     strncpy(heap->fs_table[i].name, name, sizeof heap->fs_table[i].name);
  474.  
  475.     heap->fs_table[i].name[(sizeof heap->fs_table[i].name)-1] = 0;
  476.  
  477.     heap->last_alloc = i;
  478.  
  479.     ranma();
  480.  
  481.     return i;
  482. }
  483.  
  484. void CVDubServerLink::DestroyFrameServer(int handle) {
  485.     if (handle<0 || handle>=MAXIMUM_FRAMESERVERS)
  486.         return;
  487.  
  488.     ranko();
  489.  
  490.     heap->fs_table[handle].hwndServer = NULL;
  491.  
  492.     ranma();
  493. }
  494.  
  495. __declspec(dllexport) IVDubServerLink *GetDubServerInterface() {
  496.     return &i_dubserver;
  497. }
  498.